home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1999 / MacHack 1999.toast / The Hacks / DesktopDoubler / Nub / Nub.c < prev    next >
C/C++ Source or Header  |  1999-06-25  |  6KB  |  306 lines

  1. #define DISABLE_LOCAL_CALLTRACE        1        // Set to 1 to disable Call Traces for this file.
  2. #define DISABLE_LOCAL_DEBUG            0        // Set to 1 to disable all debugging for this file.
  3. #include "DebugUtils.h"
  4.  
  5. #include <Errors.h>
  6. #include <Gestalt.h>
  7. #include "ContextUtils.h"
  8. #include "DesktopDoubler.h"
  9. #include "Nub.h"
  10. #include "PatchHarness.h"
  11. #include "ProcInfo.h"
  12. #include "Version.h"
  13.  
  14.  
  15.  
  16.  
  17.  
  18. #ifdef __cplusplus
  19. extern "C" {
  20. #endif
  21.  
  22. extern void    __InitCode__(void);
  23. extern void    __destroy_global_chain(void);
  24.  
  25. #if APPBUILD
  26.     OSStatus NubMain(Handle code);
  27. #else
  28.     pascal OSStatus main(Handle code);
  29. #endif
  30.  
  31. static OSStatus LoadNub(Handle code);
  32. static pascal OSStatus UnloadNub(Handle *code);
  33. static Boolean isPressed(UInt8 keyCode);
  34.  
  35. #if GENERATING68K && !GENERATINGCFM && __A5__
  36.     void RememberA5(void);
  37. #endif
  38.  
  39. #ifdef __cplusplus
  40. }
  41. #endif
  42.  
  43.  
  44.  
  45.  
  46.  
  47. #if GENERATINGPOWERPC
  48.     ProcInfoType                            __procinfo = uppNubLoadProcInfo;
  49.     static RoutineDescriptor                gUnloadNubRD = BUILD_ROUTINE_DESCRIPTOR(uppNubUnloadProcInfo,UnloadNub);
  50.     static RoutineDescriptor                *gUnloadNubUPP = (RoutineDescriptor*)&gUnloadNubRD;
  51. #else
  52.     static NubUnloadUPP                        gUnloadNubUPP = UnloadNub;
  53. #endif
  54.  
  55.  
  56. NubInfo                                        *gInfo = NULL;
  57. static Handle                                gCode = NULL;
  58. static UInt32                                gAbortLoad = 0;
  59. static Boolean                                gBootInstall = false;
  60. static Boolean                                gDestructOnUnload = false;
  61.  
  62.  
  63.  
  64.  
  65.  
  66. #if APPBUILD
  67.     OSStatus NubMain(Handle code)
  68.     #pragma mark NubMain
  69. #else
  70.     pascal OSStatus main(Handle code)
  71. #endif
  72. {
  73. #if !APPBUILD
  74.     GlobalContext    globals;
  75. #endif
  76.     OSStatus        err;
  77.     
  78.     
  79.     #if DEBUG
  80.         // Check for CapsLock.
  81.         if (isPressed(0x39))
  82.         {
  83.             DebugStr("\pNub abort checkpoint");
  84.             if (gAbortLoad)
  85.             {
  86.                 dprintf(kDConPrefix "LoadNub aborted\n");
  87.                 return -1;
  88.             }
  89.         }
  90.     #endif
  91.     
  92.     // Save application global A5 world.
  93.     #if GENERATING68K && !GENERATINGCFM && __A5__
  94.         RememberA5();
  95.     #endif
  96.     
  97.     // 68K code resources need to construct their own static C++ data objects (A4 must be
  98.     // setup).  We only need to do this for 68K because it'll be automagically constructed
  99.     // by the CFM init routine for a PowerPC code resource.
  100.     #if !GENERATINGPOWERPC && !APPBUILD
  101.         __InitCode__();
  102.     #endif
  103.     
  104.     // Install the Nub, if this fails we just forward the error.
  105.     // Our caller has already detached us and if we return an error it
  106.     // is responsible for unloading us, otherwise we will stick around.
  107.     err = LoadNub(code);
  108.     if (err != noErr)    
  109.     {
  110.         dprintf(kDConPrefix "LoadNub failed: %ld\n",err);
  111.         // Code resources need to destruct their own static C++ data objects (A4 must be
  112.         // setup for 68K).  We must do this PowerPC code resources too, as CFM termination
  113.         // routines won't be invoked when a code resource is unloaded.
  114.         #if !APPBUILD
  115.             __destroy_global_chain();
  116.         #endif
  117.     }
  118.     else
  119.         gDestructOnUnload = true;
  120.     
  121.     return err;
  122. }
  123.  
  124.  
  125.  
  126.  
  127.  
  128. OSStatus LoadNub(Handle code)
  129. {
  130.     THzContext    zone(SystemZone());
  131.     NubInfo        *info;
  132.     SInt32        result;
  133.     OSStatus    err;
  134.     
  135.     
  136.     // Check Gestalt to determine install/reinstall.
  137.     err = Gestalt(kNubSelector,(SInt32*)&info);
  138.     if (err != noErr)
  139.         info = NULL;
  140.     
  141.     // The INIT must be loaded first to bootstrap the debugging application version,
  142.     // otherwise we won't be able to install any patches.
  143.     #if APPBUILD
  144.         if ((err != noErr) || (info == NULL))
  145.             return notOpenErr;
  146.     #endif
  147.     
  148.     // Check for Nub already being present and loaded.
  149.     if ((err == noErr) && info && (info->signature == kNubSignature))
  150.         return opWrErr;
  151.     
  152.     // If the Gestalt selector didn't exist, or the permanent data structures haven't
  153.     // been setup (which means we haven't patched anything yet), this is an install.
  154.     if ((err != noErr) || (info == NULL))
  155.     {
  156.         if (info == NULL)
  157.         {
  158.             // Allocate system exposed permanent data structures.
  159.             info = (NubInfo*)NewPtrSysClear(sizeof(NubInfo));
  160.             if (info == NULL)
  161.             {
  162.                 err = MemError();
  163.                 dprintf(kDConPrefix "Couldn't allocate NubInfo: %ld\n",err);
  164.                 return err;
  165.             }
  166.         }
  167.         
  168.         if (err != noErr)
  169.         {
  170.             // Install system wide patch harness.
  171.             err = InstallPatchHarness(&info->patchList);
  172.             if (err != noErr)
  173.             {
  174.                 dprintf(kDConPrefix "InstallPatchHarness failed: %ld\n",err);
  175.                 DisposePtr((Ptr)info);
  176.                 return err;
  177.             }
  178.         }
  179.         
  180.         // Setup pointer to NubInfo as Gestalt selector result.
  181.         err = InstallPatch(info->patchList,'GSEL',(UniversalProcPtr)info);
  182.         if (err != noErr)
  183.         {
  184.             dprintf(kDConPrefix "Couldn't install '.4%s' Gestalt selector: %ld\n",err);
  185.             DisposePtr((Ptr)info);
  186.             return err;
  187.         }
  188.         
  189.         // Set boot time flag.
  190.         gBootInstall = true;
  191.     }
  192.     
  193.     // Setup globals.
  194.     gCode = code;
  195.     gInfo = info;
  196.         
  197.     // Setup NubInfo record.
  198.     gInfo->signature = kNubSignature;
  199.     *(UInt32*)&gInfo->version = kNubVersion;
  200.     *(UInt32*)&gInfo->compatible = kNubCompatible;
  201.     gInfo->unloadProc = gUnloadNubUPP;
  202.     
  203.     // Make it go....
  204.     err = InitDesktopDoubler();
  205.     if (err != noErr)
  206.     {
  207.         dprintf(kDConPrefix,"InitDesktopDoubler failed: %ld\n",err);
  208.         UnloadNub(&gCode);
  209.         return err;
  210.     }
  211.     
  212.     #if DEBUG
  213.     {
  214.         UInt32    vers = kNubVersion;
  215.         char    text[32];
  216.         
  217.         dprintf(kDConPrefix "DesktopDoubler %s installed\n",NumVersionToCString(text,(NumVersion*)&vers));
  218.     }
  219.     #endif
  220.     
  221.     return noErr;
  222. }
  223.  
  224.  
  225.  
  226.  
  227.  
  228. pascal OSStatus UnloadNub(Handle *code)
  229. {
  230.     GlobalContext    globals;
  231.     THzContext        zone(SystemZone());
  232.     PatchDesc        *patch;
  233.     
  234.     
  235.     // Make it stop...
  236.     TermDesktopDoubler();
  237.     
  238.     // Remove all patches.
  239.     patch = gInfo->patchList;
  240.     while(patch != NULL)
  241.     {
  242.         // Don't remove our special GestaltSelector patch.
  243.         if ((patch->type != 'GSEL') && patch->remove)
  244.             CallPatchRemoveProc(patch->remove,patch);
  245.         
  246.         patch = patch->next;
  247.     }
  248.     
  249.     // Clear NubInfo record.
  250.     gInfo->signature = 0;
  251.     gInfo->unloadProc = NULL;
  252.     
  253.     // Caller must dispose.
  254.     #if APPBUILD
  255.         *code = NULL;
  256.     #else
  257.         *code = gCode;
  258.     #endif
  259.     
  260.     if (gDestructOnUnload)
  261.     {
  262.         // Code resources need to destruct their own static C++ data objects (A4 must be
  263.         // setup for 68K).  We must do this PowerPC code resources too, as CFM termination
  264.         // routines won't be invoked when a code resource is unloaded.
  265.         #if !APPBUILD
  266.             __destroy_global_chain();
  267.         #endif
  268.         gDestructOnUnload = false;
  269.     }
  270.     
  271.     return noErr;
  272. }
  273.  
  274.  
  275.  
  276.  
  277.  
  278. Boolean isPressed(UInt8 keyCode)
  279. {
  280.     UInt8    km[16];
  281.     
  282.     
  283.     GetKeys((SInt32*)&km[0]);
  284.     return ((km[keyCode >> 3] >> (keyCode & 7)) & 1);
  285. }
  286.  
  287.  
  288.  
  289.  
  290.  
  291. #if GENERATING68K && !GENERATINGCFM && __A5__
  292.     asm void RememberA5(void)
  293.     {
  294.         LEA            @A5Storage,A0
  295.         MOVE.L        A5,(A0)
  296.         RTS
  297.         
  298.     entry GetCurrentA5
  299.         MOVE.L        @A5Storage,D0
  300.         RTS
  301.         
  302.     @A5Storage:
  303.         DC.L        0x00000000
  304.     }
  305. #endif
  306.